package org.wu.framework.lazy.orm.core.factory;

import org.wu.framework.core.CamelAndUnderLineConverter;
import org.wu.framework.core.ReflexUtils;
import org.wu.framework.core.exception.AssertFactory;
import org.wu.framework.core.utils.ObjectUtils;
import org.wu.framework.lazy.orm.core.persistence.conf.LazyTableEndpoint;
import org.wu.framework.lazy.orm.core.persistence.conf.LazyTableFieldEndpoint;
import org.wu.framework.lazy.orm.core.persistence.conf.LazyTableStructure;
import org.wu.framework.lazy.orm.core.persistence.conf.LazyTableWeakStructure;
import org.wu.framework.lazy.orm.core.persistence.conf.mysql.FieldLazyTableFieldEndpoint;
import org.wu.framework.lazy.orm.core.persistence.map.EasyHashMap;
import org.wu.framework.lazy.orm.core.persistence.util.LazySQLUtil;
import org.wu.framework.lazy.orm.core.source.adapter.SourceFactory;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

/**
 * LazyTableStructure 对象转换工厂
 */
public class LazyTableStructureConverterFactory {


    /**
     * 将对象转换成 Persistence 对象
     *
     * @param source 原始数据 数组、对象、Map
     * @return LazyTableStructure 惰性表结构
     */
    public static LazyTableStructure dataStructure(Object source) {
        AssertFactory.notNull(source, "source 数据不能为空");
        final Class<?> sourceClass = source.getClass();
        if (Collection.class.isAssignableFrom(sourceClass)) {
            return LazyTableStructureConverterFactory.wrapperIterable((Iterable<?>) source);
        } else if (EasyHashMap.class.isAssignableFrom(sourceClass)) {
            return LazyTableStructureConverterFactory.wrapperEasyHashMap((EasyHashMap<?, ?>) source);
        } else if (sourceClass.isArray()) {
            return LazyTableStructureConverterFactory.wrapperArray((Object[]) source);
        } else {
            return LazyTableStructureConverterFactory.wrapperBean(source);
        }
    }


    /**
     * 解析 转换数组
     *
     * @param iterable 原始数据迭代器
     * @return LazyTableStructure 惰性表结构
     */
    public static LazyTableStructure wrapperIterable(Iterable<?> iterable) {
        Object next = iterable.iterator().next();
        Class<?> nextClass = next.getClass();
        // 首次计算
        boolean isBean;
        // 解析数据schema
        LazyTableEndpoint lazyTableEndpoint = null;
        if (EasyHashMap.class.isAssignableFrom(nextClass)) {
            isBean = false;
            final LazyTableStructure lazyTableStructure = wrapperEasyHashMap((EasyHashMap<?, ?>) next);
            lazyTableEndpoint = lazyTableStructure.schema();

        } else if (Object.class.isAssignableFrom(nextClass)) {
            isBean = true;
            final LazyTableStructure lazyTableStructure = wrapperBean(next);
            lazyTableEndpoint = lazyTableStructure.schema();
        } else {
            isBean = false;
        }

        // 解析负载数据
        List<List<LazyTableFieldEndpoint>> fieldValueList =
                StreamSupport
                        .stream(iterable.spliterator(), true)
                        .parallel()
                        .map(o -> {
                            LazyTableStructure lazyTableStructure;
                            if (isBean) {
                                // bean
                                lazyTableStructure = wrapperBean(o);
                            } else {
                                // map
                                lazyTableStructure = wrapperEasyHashMap((EasyHashMap<?, ?>) o);
                            }
                            return lazyTableStructure.payload().getFirst();

                        }).toList();

        return new LazyTableStructure(lazyTableEndpoint, fieldValueList);
    }


    /**
     * 解析数组
     *
     * @param array 原始数据
     * @return LazyTableStructure 惰性表结构
     */
    private static LazyTableStructure wrapperArray(Object[] array) {
        final Object next = array[0];
        final Class<?> nextClass = next.getClass();
        List<List<LazyTableFieldEndpoint>> fieldValueList = new ArrayList<>();
        // 首次计算
        boolean hasCalculation = false;
        // 数据schema
        LazyTableEndpoint lazyTableEndpoint = null;
        if (EasyHashMap.class.isAssignableFrom(nextClass)) {
            for (Object o : array) {

                final LazyTableStructure lazyTableStructure = wrapperEasyHashMap((EasyHashMap<?, ?>) o);
                if (!hasCalculation) {
                    hasCalculation = true;
                    lazyTableEndpoint = lazyTableStructure.schema();
                }
                fieldValueList.add(lazyTableStructure.payload().get(0));
            }
        } else if (Object.class.isAssignableFrom(nextClass)) {
            for (Object o : array) {
                final LazyTableStructure lazyTableStructure = wrapperBean(o);
                if (!hasCalculation) {
                    hasCalculation = true;
                    lazyTableEndpoint = lazyTableStructure.schema();
                }
                fieldValueList.add(lazyTableStructure.payload().get(0));
            }
        }

        return new LazyTableStructure(lazyTableEndpoint, fieldValueList);
    }

    /**
     * 解析 EasyHashMap 为 LazyTableStructure数据结构
     *
     * @param easyHashMap 原始数据map
     * @return LazyTableStructure 惰性表结构
     */
    public static LazyTableStructure wrapperEasyHashMap(EasyHashMap<?, ?> easyHashMap) {
        LazyTableEndpoint lazyTableEndpoint = easyHashMap.toEasyTableAnnotation(false, true);
        List<LazyTableFieldEndpoint> fieldLazyTableFieldEndpointList = easyHashMap.getFieldLazyTableFieldEndpointList();
        List<FieldLazyTableFieldEndpoint> thisFieldEndpointList = lazyTableEndpoint.toThisFieldEndpointList(fieldLazyTableFieldEndpointList);
        return new LazyTableStructure(lazyTableEndpoint, Arrays.asList(fieldLazyTableFieldEndpointList));
    }

    /**
     * 解析对象
     *
     * @param o 原始数据
     * @return LazyTableStructure 惰性表结构
     */
    public static LazyTableStructure wrapperBean(Object o) {
        AssertFactory.notNull(o, "source 数据不能为空");
        Class<?> oClass = o.getClass();
        LazyTableEndpoint<? extends LazyTableFieldEndpoint> lazyTableEndpoint = SourceFactory.defaultAnalyzeLazyTableFromClass(oClass);
        List<LazyTableFieldEndpoint> fieldValueList = lazyTableEndpoint
                .getLazyTableFieldEndpointList()
                .stream()
                .filter(LazyTableFieldEndpoint::isExist)
//                filter(fieldLazyTableFieldEndpoint -> !LazyTableFieldId.IdType.AUTOMATIC_ID.equals(fieldLazyTableFieldEndpoint.getIdType())).
                .map(fieldLazyTableFieldEndpoint -> {
                    try {
                        LazyTableFieldEndpoint clone = fieldLazyTableFieldEndpoint.clone();
                        Field field = clone.getField();
                        Object fieldValue = field.get(o);
                        clone.setFieldValue(fieldValue);
                        return clone;
                    } catch (IllegalAccessException | CloneNotSupportedException e) {
                        e.printStackTrace();
                    }
                    return null;
                }).toList();

        return new LazyTableStructure(lazyTableEndpoint, List.of(fieldValueList));
    }


    /**
     * 将对象转换成 Persistence 对象
     *
     * @param source 原始数据 数组、对象、Map
     * @return LazyTableStructure 惰性表结构
     */
    public static LazyTableWeakStructure weakDataStructure(Object source) {
        AssertFactory.notNull(source, "source 数据不能为空");
        final Class<?> sourceClass = source.getClass();
        if (Collection.class.isAssignableFrom(sourceClass)) {
            return LazyTableStructureConverterFactory.wrapperWeakIterable((Iterable<?>) source);
        } else if (Map.class.isAssignableFrom(sourceClass)) {
            return LazyTableStructureConverterFactory.wrapperWeakSingleMap((Map<?, ?>) source);
        } else if (sourceClass.isArray()) {
            return LazyTableStructureConverterFactory.wrapperWeakArray((Object[]) source);
        } else {
            return LazyTableStructureConverterFactory.wrapperWeakSingleBean(source);
        }
    }

    /**
     * 解析 转换数组
     *
     * @param iterable 原始数据迭代器
     * @return LazyTableStructure 惰性表结构
     */
    public static LazyTableWeakStructure wrapperWeakIterable(Iterable<?> iterable) {
        Object next = iterable.iterator().next();
        Class<?> nextClass = next.getClass();
        // 首次计算
        boolean isBean;
        // 解析数据schema
        List<String> schema = null;
        if (Map.class.isAssignableFrom(nextClass)) {
            isBean = false;
            LazyTableWeakStructure lazyTableStructure = wrapperWeakSingleMap((Map<?, ?>) next);
            schema = lazyTableStructure.schema();

        } else if (Object.class.isAssignableFrom(nextClass)) {
            isBean = true;
            LazyTableWeakStructure lazyTableStructure = wrapperWeakSingleBean(next);
            schema = lazyTableStructure.schema();
        } else {
            isBean = false;
        }


        // 解析负载数据
        List<Map<String/*column*/, Object/*value*/>> fieldValueList =
                StreamSupport
                        .stream(iterable.spliterator(), true)
                        .parallel()
                        .map(o -> {
                            LazyTableWeakStructure lazyTableStructure;
                            if (isBean) {
                                // bean
                                lazyTableStructure = wrapperWeakSingleBean(o);
                            } else {
                                // map
                                lazyTableStructure = wrapperWeakSingleMap((Map<?, ?>) o);
                            }
                            return lazyTableStructure.payload().getFirst();

                        }).toList();

        return new LazyTableWeakStructure(schema, fieldValueList);
    }

    /**
     * 解析数组
     *
     * @param array 原始数据
     * @return LazyTableStructure 惰性表结构
     */
    private static LazyTableWeakStructure wrapperWeakArray(Object[] array) {
        final Object next = array[0];
        final Class<?> nextClass = next.getClass();
        List<Map<String/*column*/, Object/*value*/>> fieldValueList = new ArrayList<>();
        // 首次计算
        boolean hasCalculation = false;
        // 数据schema
        List<String> schema = null;
        if (Map.class.isAssignableFrom(nextClass)) {
            for (Object o : array) {

                LazyTableWeakStructure lazyTableStructure = wrapperWeakSingleMap((Map<?, ?>) o);
                if (!hasCalculation) {
                    hasCalculation = true;
                    schema = lazyTableStructure.schema();
                }
                fieldValueList.add(lazyTableStructure.payload().getFirst());
            }
        } else if (Object.class.isAssignableFrom(nextClass)) {
            for (Object o : array) {
                LazyTableWeakStructure lazyTableStructure = wrapperWeakSingleBean(o);
                if (!hasCalculation) {
                    hasCalculation = true;
                    schema = lazyTableStructure.schema();
                }
                fieldValueList.add(lazyTableStructure.payload().getFirst());
            }
        }

        return new LazyTableWeakStructure(schema, fieldValueList);
    }

    /**
     * 解析 弱对象Map
     *
     * @param source 原始数据
     * @return 返回弱对象结构
     */
    private static LazyTableWeakStructure wrapperWeakSingleMap(Map<?, ?> source) {

        List<String> schema = new ArrayList<>();
        Map<String/*column*/, Object/*value*/> payload = new HashMap<>();
        source.entrySet().stream()
                .filter(entry -> !ObjectUtils.isEmpty(entry.getValue()))
                .forEach(entry -> {
                    Object key = entry.getKey();
                    Object value = entry.getValue();
                    // TODO 中文添加`` 问题
                    schema.add(key.toString());
                    payload.put(key.toString(), LazySQLUtil.valueToSqlValue(value));
                });

        return new LazyTableWeakStructure(schema, List.of(payload));
    }

    /**
     * 解析弱对象
     *
     * @param source 弱对象
     * @return 返回弱对象结构
     */
    private static LazyTableWeakStructure wrapperWeakSingleBean(Object source) {

        List<String> schema = new ArrayList<>();
        Map<String/*column*/, Object/*value*/> payload = new HashMap<>();
        for (Field declaredField : source.getClass().getDeclaredFields()) {
            String fieldName = declaredField.getName();
            // TODO 中文添加`` 问题
            String key = CamelAndUnderLineConverter.humpToLine2(fieldName);
            Object value = ReflexUtils.findDeclaredFieldBean(source, declaredField);
            if (ObjectUtils.isEmpty(value)) {
                continue;
            }
            schema.add(key);
            payload.put(key, LazySQLUtil.valueToSqlValue(value));

        }
        return new LazyTableWeakStructure(schema, List.of(payload));
    }

}
